﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Zatify.WebUI.Models;
using Zatify.Domain.Abstract;
using Zatify.Domain.Data;
using Zatify.WebUI.Infrastructure.Absrtact;
using Zatify.WebUI.Admin.Helpers;
using Zatify.WebUI.Infrastructure;

using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace Zatify.WebUI.Controllers
{
    public class RegistrationController : BaseController
    {
        private IZatifyRepository repository;
        private IZatifyAuthProvider authProvider;

        public RegistrationController(IZatifyRepository repository, IZatifyAuthProvider authProvider)
        {
            this.repository = repository;
            this.authProvider = authProvider;
        }

        [HttpGet]
        [Utils.MyRequireHttps]
        public ViewResult SignUp()
        {
            return View();
        }

        #region Individual User

        [HttpGet]
        public ActionResult Individual(Guid? token)
        {
            if (!token.HasValue)
            {
                return View(new IndividualViewModel());
            }
            else
            {
                var user = repository.UserGetByToken(token.Value);

                return View(new IndividualViewModel()
                {
                    UserID = user.Login,
                    Password = user.Password,
                    ConfirmPassword = user.Password,
                    Email = user.Email,
                    ZipCode = user.ZipCode,
                    Phone = user.Phone,
                    ReferredBy = user.ReferredBy
                });
            }
        }

        [HttpPost]
        public ActionResult Individual(IndividualViewModel model, string imagePath)
        {
            try
            {
                if (this.ModelState.IsValid)
                {
                    if (!String.IsNullOrWhiteSpace(imagePath))
                    {
                        var filePath = Server.MapPath(imagePath);
                        var fileInfo = new System.IO.FileInfo(filePath);

                        using (var fsStream = System.IO.File.OpenRead(filePath))
                        {
                            model.Photo = new byte[fsStream.Length];
                            model.PhotoContentType = "image/" + fileInfo.Extension.Replace(".", String.Empty);
                            if (!Utils.CheckImageMime(model.PhotoContentType))
                            {
                                this.ModelState.AddModelError("ImageTypeError", "Photo/image has not valid file type");
                            }
                            fsStream.Read(model.Photo, 0, (int)fsStream.Length);
                        }
                    }

                    if (this.ModelState.IsValid)
                    {
                        var result = repository.UserRegister(new User()
                         {
                             Login = model.UserID,
                             Password = model.Password,
                             Email = model.Email,
                             Phone = model.Phone,
                             ZipCode = model.ZipCode,
                             ReferredBy = model.ReferredBy,
                             PhotoContentType = model.PhotoContentType,
                             Photo = model.Photo
                         });

                        if (result.IdResult > 0)
                        {
                            this.authProvider.AuthenticateUser(new User()
                            {
                                Login = model.UserID,
                                Password = model.Password,
                                UserRole = UserRole.RegularUser,
                                TimeZoneOffset = model.TimeZoneOffset
                            });

                            System.IO.File.Delete(Server.MapPath(imagePath));
                            return RedirectToAction("Categories", "UserProfile");
                        }
                        else
                        {
                            switch (result.IdResult)
                            {
                                case 0:
                                    this.ModelState.AddModelError("ReferredBy", "Entered Referrer does not exist");
                                    break;
                                case -1:
                                    this.ModelState.AddModelError("Phone", "Entered Phone already exist");
                                    break;
                                case -2:
                                    this.ModelState.AddModelError("Email", "Entered Email already exist");
                                    break;
                                case -3:
                                    this.ModelState.AddModelError("ZipCode", "Entered ZipCode does not exists");
                                    break;
                            }
                        }
                    }

                }
            }
            catch (Exception ex)
            {
                this.ModelState.AddModelError("Exception", ex.Message);
            }

            return View(model);
        }

        public ActionResult IndividualUserIDUnique(string userId)
        {
            /*if (repository.Users.Any(u => u.Login.ToLower() == userId.Trim().ToLower()) || repository.Businesses.Any(b => b.Login.ToLower() == userId.Trim().ToLower()))
                return Json(String.Format("User ID \"{0}\" is already in use.", userId), JsonRequestBehavior.AllowGet);*/
            if (!repository.BusinessUser_CheckLoginEmail(userId, null))
                return Json(String.Format("User ID \"{0}\" is already in use.", userId), JsonRequestBehavior.AllowGet);
            return Json(true, JsonRequestBehavior.AllowGet);
        }

        public ActionResult IndividualUserEmailUnique(string email)
        {
            if (!repository.BusinessUser_CheckLoginEmail(null, email))
                return Json(String.Format("Email \"{0}\" is already in use.", email), JsonRequestBehavior.AllowGet);
            return Json(true, JsonRequestBehavior.AllowGet);
        }

        #endregion

        #region Business User

        private const string Business_Registration_Step1 = "Business_Registration_Step1";
        private const string Business_Registration_Step2 = "Business_Registration_Step2";
        private const string Business_Registration_Step3 = "Business_Registration_Step3";
        private const string Business_Registration_Step4 = "Business_Registration_Step4";

        private BusinessRegistrationStep1ViewModel BusinessRegistrationStep1Model
        {
            get { return (BusinessRegistrationStep1ViewModel)Session[Business_Registration_Step1]; }
            set { Session[Business_Registration_Step1] = value; }
        }

        private BusinessRegistrationStep2ViewModel BusinessRegistrationStep2Model
        {
            get { return (BusinessRegistrationStep2ViewModel)Session[Business_Registration_Step2]; }
            set { Session[Business_Registration_Step2] = value; }
        }

        private BusinessRegistrationStep3ViewModel BusinessRegistrationStep3Model
        {
            get { return (BusinessRegistrationStep3ViewModel)Session[Business_Registration_Step3]; }
            set { Session[Business_Registration_Step3] = value; }
        }

        private BusinessRegistrationStep4ViewModel BusinessRegistrationStep4Model
        {
            get { return (BusinessRegistrationStep4ViewModel)Session[Business_Registration_Step4]; }
            set { Session[Business_Registration_Step4] = value; }
        }

        [HttpGet]
        public ActionResult Business()
        {
            return RedirectToAction("BusinessRegistrationStep1");
        }

        #region 1st Step - Business Registration - General Info

        [HttpGet]
        public ActionResult BusinessRegistrationStep1()
        {
            PopulateUSStatesViewData(null);

            return View(new BusinessRegistrationStep1ViewModel());
        }
        [HttpPost]
        public ActionResult BusinessRegistrationStep1(BusinessRegistrationStep1ViewModel model)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    var businessCoordinates = this.repository.Business_GetCoordinates(model.StreetAddress1, model.StreetAddress2, model.City, model.StateCode, model.ZipCode);

                    var result = this.repository.Business_RegisterStep1(model.UserID, model.Password, model.Email, model.BusinessName, model.Web ?? String.Empty,
                        model.BusinessPhone, model.CellPhone ?? String.Empty, model.TollFreePhone, model.Fax,
                        model.StreetAddress1, model.StreetAddress2, model.City, model.StateCode, model.ZipCode, businessCoordinates.Long, businessCoordinates.Lat, null);

                    if (result.IdResult == 1)
                    {
                        model.SecurityToken = result.SecurityToken.Value;
                        BusinessRegistrationStep1Model = model;

                        return RedirectToAction("BusinessRegistrationStep2");
                    }
                    else
                    {
                        switch (result.IdResult)
                        {
                            case -3:
                                this.ModelState.AddModelError("ZipCode", "Entered ZipCode does not exist");
                                break;
                            case -2:
                                this.ModelState.AddModelError("Email", "Entered Email already exist");
                                break;
                        }
                    }
                }
                PopulateUSStatesViewData(model.StateCode);
            }
            catch(Exception ex)
            {
                this.ModelState.AddModelError("Exception", ex.Message);
            }

            return View(model);
        }

        #endregion

        #region 2nd Step - Business Registration - Business Hours & Image/Photo

        [HttpGet]
        public ActionResult BusinessRegistrationStep2()
        {
            if (BusinessRegistrationStep1Model == null)
                return RedirectToAction("BusinessRegistrationStep1");
            
            var defaultBussinesHoursFrom = this.repository.SystemDefaultsGetBusinessHourFrom();
            var defaultBussinesHoursTo = this.repository.SystemDefaultsGetBusinessHourTo();

            PopulateBusinessHoursViewData();

            return View(new BusinessRegistrationStep2ViewModel()
            {
                MonFrom = defaultBussinesHoursFrom,
                MonTo = defaultBussinesHoursTo,
                TueFrom = defaultBussinesHoursFrom,
                TueTo = defaultBussinesHoursTo,
                WedFrom = defaultBussinesHoursFrom,
                WedTo = defaultBussinesHoursTo,
                ThuFrom = defaultBussinesHoursFrom,
                ThuTo = defaultBussinesHoursTo,
                FriFrom = defaultBussinesHoursFrom,
                FriTo = defaultBussinesHoursTo,
                SatFrom = defaultBussinesHoursFrom,
                SatTo = defaultBussinesHoursTo,
                SunFrom = defaultBussinesHoursFrom,
                SunTo = defaultBussinesHoursTo,
            });
        }
        [HttpPost]
        public ActionResult BusinessRegistrationStep2(BusinessRegistrationStep2ViewModel model, string imagePath)
        {
            if (BusinessRegistrationStep1Model == null)
                return RedirectToAction("BusinessRegistrationStep1");

            try
            {
                if (!model.MonClosed && !model.Mon24HoursOpen && (model.MonTo == model.MonFrom /*|| model.MonTo < model.MonFrom*/))
                {
                    this.ModelState.AddModelError("MonTimeError", "Monday working time incorrect");
                }
                if (!model.TueClosed && !model.Tue24HoursOpen && (model.TueTo == model.TueFrom /*|| model.TueTo < model.TueFrom*/))
                {
                    this.ModelState.AddModelError("TueTimeError", "Tuesday working time incorrect");
                }
                if (!model.WedClosed && !model.Wed24HoursOpen && (model.WedTo == model.WedFrom /*|| model.WedTo < model.WedFrom*/))
                {
                    this.ModelState.AddModelError("WedTimeError", "Wednesday working time incorrect");
                }
                if (!model.ThuClosed && !model.Thu24HoursOpen && (model.ThuTo == model.ThuFrom /*|| model.ThuTo < model.ThuFrom*/))
                {
                    this.ModelState.AddModelError("ThuTimeError", "Thursday working time incorrect");
                }
                if (!model.FriClosed && !model.Fri24HoursOpen && (model.FriTo == model.FriFrom /*|| model.FriTo < model.FriFrom*/))
                {
                    this.ModelState.AddModelError("FriTimeError", "Friday working time incorrect");
                }
                if (!model.SatClosed && !model.Sat24HoursOpen && (model.SatTo == model.SatFrom /*|| model.SatTo < model.SatFrom*/))
                {
                    this.ModelState.AddModelError("SatTimeError", "Saturday working time incorrect");
                }
                if (!model.SunClosed && !model.Sun24HoursOpen && (model.SunTo == model.SunFrom /*|| model.SunTo < model.SunFrom*/))
                {
                    this.ModelState.AddModelError("SunTimeError", "Sunday working time incorrect");
                }

                if (ModelState.IsValid)
                {
                    if (this.UploadedTempImageBytes == null)
                    {
                        this.ModelState.AddModelError("ImageEmptyError", "Picture is mandatory");
                    }

                    if (ModelState.IsValid)
                    {
                        if ((this.UploadedTempImageBytes != null && this.UploadedTempImageBytes.Length > 0) && !String.IsNullOrEmpty(this.UploadedTempImageMimeType))
                        {
                            model.Picture = this.UploadedTempImageBytes;
                            model.PictureContentType = this.UploadedTempImageMimeType;
                            if (!Utils.CheckImageMime(model.PictureContentType))
                            {
                                this.ModelState.AddModelError("ImageTypeError", "Photo/image has not valid file type");
                            }
                        }
                    }

                    if (ModelState.IsValid)
                    {
                        model.ReferredBy = model.ReferredBy ?? String.Empty;

                        BusinessRegistrationStep2Model = model;

                        return RedirectToAction("BusinessRegistrationStep3");
                    }
                }

            }
            catch (Exception ex)
            {
                this.ModelState.AddModelError("Exception", ex.Message);
            }

            PopulateBusinessHoursViewData();
            return View(model);
        }

        #endregion

        #region 3rd Step - Business Registration - Categories

        [HttpGet]
        public ActionResult BusinessRegistrationStep3(int? categoryId)
        {
            if (BusinessRegistrationStep2Model == null)
                return RedirectToAction("BusinessRegistrationStep2");

            return View(new BusinessRegistrationStep3CategoriesViewModel()
            {
                CurrentCategory = repository.Categories.FirstOrDefault(c => c.CategoryId == categoryId),
                Categories = repository.CategoriesGetAll().Where(c => c.ParentId == categoryId).OrderBy(c => c.SortOrder).ToList()
            });
        }
        [HttpPost]
        public ActionResult BusinessRegistrationStep3(BusinessRegistrationStep3ViewModel model)
        {
            if (BusinessRegistrationStep2Model == null)
                return RedirectToAction("BusinessRegistrationStep2");

            if (ModelState.IsValid)
            {
                BusinessRegistrationStep3Model = model;

                return RedirectToAction("BusinessRegistrationStep4");
            }

            return RedirectToAction("BusinessRegistrationStep3");
        }

        #endregion

        #region 4th Step - Business Registration - Check Out(TEMPORARY NOT WORKING)

        [HttpGet]
        public ActionResult BusinessRegistrationStep4()
        {
            if (BusinessRegistrationStep3Model == null)
                return RedirectToAction("BusinessRegistrationStep3");

            BusinessRegistrationStep4Model = new BusinessRegistrationStep4ViewModel();

            return RedirectToAction("BusinessRegistrationStep5");
            //return View(new BusinessRegistrationStep4ViewModel());
        }
        // TEMPORARY NOT WORKING
        [HttpPost]
        public ActionResult BusinessRegistrationStep4(BusinessRegistrationStep4ViewModel model)
        {
            if (BusinessRegistrationStep3Model == null)
                return RedirectToAction("BusinessRegistrationStep3");

            if (ModelState.IsValid)
            {
                BusinessRegistrationStep4Model = model;

                return RedirectToAction("BusinessRegistrationStep5");
            }

            return View(model);
        }

        #endregion

        #region 5th - Business Registration - Payment Info

        [HttpGet]
        public ActionResult BusinessRegistrationStep5()
        {
            if (BusinessRegistrationStep4Model == null)
                return RedirectToAction("BusinessRegistrationStep4");

            PopulateUSStatesViewData(null);
            PopulateDatePicker(0, 0);

            return View(new BusinessRegistrationStep5ViewModel()
            {
                BusinessAddress1 = BusinessRegistrationStep1Model.StreetAddress1,
                BusinessAddress2 = BusinessRegistrationStep1Model.StreetAddress2,
                BusinessCity = BusinessRegistrationStep1Model.City,
                BusinessStateCode = BusinessRegistrationStep1Model.StateCode,
                BusinessZipCode = BusinessRegistrationStep1Model.ZipCode
            });
        }
        [HttpPost]
        public ActionResult BusinessRegistrationStep5(BusinessRegistrationStep5ViewModel model)
        {
            if (Session[Business_Registration_Step4] == null)
                return RedirectToAction("BusinessRegistrationStep4");

            try
            {
                if ((model.CreditCardExpirationYear < DateTime.Now.Year) || (model.CreditCardExpirationYear == DateTime.Now.Year && model.CreditCardExpirationMonth <= DateTime.Now.Month))
                {
                    ModelState.AddModelError("CreditCardExpirationDate", "Credit card expired");
                }

                if (ModelState.IsValid)
                {
                    var businessCoordinates = this.repository.Business_GetCoordinates(BusinessRegistrationStep1Model.StreetAddress1, BusinessRegistrationStep1Model.StreetAddress2,
                        BusinessRegistrationStep1Model.City, BusinessRegistrationStep1Model.StateCode, BusinessRegistrationStep1Model.ZipCode);

                    var result = this.repository.Business_RegisterStep2(BusinessRegistrationStep1Model.SecurityToken, BusinessRegistrationStep2Model.Description, BusinessRegistrationStep2Model.ReferredBy,
                        new BusinessHours()
                        {
                            SunFrom = BusinessRegistrationStep2Model.SunFrom,
                            SunTo = BusinessRegistrationStep2Model.SunTo,
                            SunClosed = BusinessRegistrationStep2Model.SunClosed,
                            MonFrom = BusinessRegistrationStep2Model.MonFrom,
                            MonTo = BusinessRegistrationStep2Model.MonTo,
                            MonClosed = BusinessRegistrationStep2Model.MonClosed,
                            TueFrom = BusinessRegistrationStep2Model.TueFrom,
                            TueTo = BusinessRegistrationStep2Model.TueTo,
                            TueClosed = BusinessRegistrationStep2Model.TueClosed,
                            WedFrom = BusinessRegistrationStep2Model.WedFrom,
                            WedTo = BusinessRegistrationStep2Model.WedTo,
                            WedClosed = BusinessRegistrationStep2Model.WedClosed,
                            ThuFrom = BusinessRegistrationStep2Model.ThuFrom,
                            ThuTo = BusinessRegistrationStep2Model.ThuTo,
                            ThuClosed = BusinessRegistrationStep2Model.ThuClosed,
                            FriFrom = BusinessRegistrationStep2Model.FriFrom,
                            FriTo = BusinessRegistrationStep2Model.FriTo,
                            FriClosed = BusinessRegistrationStep2Model.FriClosed,
                            SatFrom = BusinessRegistrationStep2Model.SatFrom,
                            SatTo = BusinessRegistrationStep2Model.SatTo,
                            SatClosed = BusinessRegistrationStep2Model.SatClosed
                        },
                        BusinessRegistrationStep3Model.SelectegCategoriesIds,
                        (BusinessRegistrationStep3Model.NewCategoryName1IsChecked ? BusinessRegistrationStep3Model.NewCategoryName1 : String.Empty),
                        (BusinessRegistrationStep3Model.NewCategoryName2IsChecked ? BusinessRegistrationStep3Model.NewCategoryName2 : String.Empty),
                        (BusinessRegistrationStep3Model.NewCategoryName3IsChecked ? BusinessRegistrationStep3Model.NewCategoryName3 : String.Empty),
                        model.CreditCardNo,
                        new DateTime(model.CreditCardExpirationYear, model.CreditCardExpirationMonth, 1),// <--- model.CreditCardExpDate,
                        model.CreditCardName, model.CreditCardPin, model.BillingUse, model.BillingAddress1, model.BillingAddress2 ?? String.Empty, model.BillingCity,
                        (model.BillingUse ? BusinessRegistrationStep1Model.StateCode : model.BillingStateCode),
                        model.BillingZipCode,
                        BusinessRegistrationStep2Model.PictureContentType ?? String.Empty, BusinessRegistrationStep2Model.Picture, businessCoordinates.Lat, businessCoordinates.Long);

                    if (result == 1)
                    {
                        this.authProvider.AuthenticateUser(new User()
                        {
                            Login = BusinessRegistrationStep1Model.UserID,
                            Password = BusinessRegistrationStep1Model.Password,
                            RememberUser = true,
                            UserRole = UserRole.BusinessUser,
                            TimeZoneOffset = BusinessRegistrationStep1Model.TimeZoneOffset
                        });

                        BusinessRegistrationStep1Model = null;
                        BusinessRegistrationStep2Model = null;
                        BusinessRegistrationStep3Model = null;
                        BusinessRegistrationStep4Model = null;

                        return RedirectToAction("Index", "Home");
                    }
                    else
                    {
                        switch (result)
                        {
                            case 0:
                                this.ModelState.AddModelError("ReferrencedBy", "Entered Referrer does not exist");
                                PopulateBusinessHoursViewData();
                                return View("BusinessRegistrationStep2", BusinessRegistrationStep2Model);
                            case -4:
                                this.ModelState.AddModelError("Email", "Entered Billing Zip Code does not exist");
                                break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                this.ModelState.AddModelError("Exception", ex.Message);
            }

            PopulateUSStatesViewData(null);
            PopulateDatePicker(0, 0);

            return View(model);
        }

        #endregion

        public ActionResult BusinessUserIDUnique(string userId)
        {
            //if (repository.Businesses.Any(b => b.Login.ToLower() == userId.Trim().ToLower()) || repository.Users.Any(u => u.Login.ToLower() == userId.Trim().ToLower()))
            if (!repository.BusinessUser_CheckLoginEmail(userId, null))
                return Json(String.Format("User ID \"{0}\" is already in use.", userId), JsonRequestBehavior.AllowGet);

            return Json(true, JsonRequestBehavior.AllowGet);
        }

        public ActionResult BusinessEmailUnique(string email)
        {
            if (!repository.BusinessUser_CheckLoginEmail(null, email))
                return Json(String.Format("Email \"{0}\" is already in use.", email), JsonRequestBehavior.AllowGet);

            return Json(true, JsonRequestBehavior.AllowGet);
        }

        #region Methods

        private void PopulateBusinessHoursViewData()
        {
            ViewData["BusinessHours"] = Helper.GetBusinessHoursSelectList();
        }

        private void PopulateUSStatesViewData(string stateCode)
        {
            ViewData["USStates"] =
                (from state in repository.USStates
                 select new SelectListItem()
                 {
                     Text = state.StateName,
                     Value = state.StateCode,
                     Selected = (!String.IsNullOrEmpty(stateCode) && state.StateCode == stateCode)
                 }).ToList();
        }

        private void PopulateDatePicker(int month, int year)
        {
            var months = new List<SelectListItem>();
            var years = new List<SelectListItem>();

            for (int i = 1; i <= 12; i++)
            {
                months.Add(new SelectListItem()
                {
                    Text = i.ToString(),
                    Value = i.ToString(),
                    Selected = i == month
                });
            }

            ViewData["Months"] = months;

            for (int i = DateTime.Now.Year; i <= (DateTime.Now.Year + 10); i++)
            {
                years.Add(new SelectListItem()
                {
                    Text = i.ToString(),
                    Value = i.ToString(),
                    Selected = i == year
                });
            }

            ViewData["Years"] = years;
        }

        #endregion

        #endregion
    }
}
